package l1j.server.server.model.shop;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;



import java.util.logging.Level;


import java.util.logging.Logger;

import l1j.opqlo.Server.L1World.L1World;
import l1j.server.Config;
import l1j.server.server.GetNowTime;
import l1j.server.server.datatables.CastleTable;
import l1j.server.server.datatables.ItemTable;
import l1j.server.server.datatables.ShopTable;
import l1j.server.server.datatables.TownTable;
import l1j.server.server.model.L1CastleLocation;
import l1j.server.server.model.L1PcInventory;
import l1j.server.server.model.L1TaxCalculator;
import l1j.server.server.model.L1TownLocation;
import l1j.server.server.model.Instance.L1ItemInstance;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.model.game.L1BugBearRace;
import l1j.server.server.model.item.L1ItemId;
import l1j.server.server.serverpackets.S_ServerMessage;
import l1j.server.server.serverpackets.S_SystemMessage;
import l1j.server.server.templates.L1Castle;
import l1j.server.server.templates.L1Item;
import l1j.server.server.templates.L1ShopItem;
import l1j.server.server.utils.IntRange;
import l1j.server.server.utils.Random;
import l1j.server.server.utils.StreamUtil;

public class L1Shop {
	private final int _npcId;
	private final List<L1ShopItem> _sellingItems;
	private final List<L1ShopItem> _purchasingItems;

	public L1Shop(final int npcId, final List<L1ShopItem> sellingItems,final List<L1ShopItem> purchasingItems) {
		if (sellingItems == null || purchasingItems == null) {
			throw new NullPointerException();
		}

		_npcId = npcId;
		_sellingItems = sellingItems;
		_purchasingItems = purchasingItems;
	}

	public int getNpcId() {
		return _npcId;
	}

	public List<L1ShopItem> getSellingItems() {
		return _sellingItems;
	}

	/**
	 * この商店で、指定されたアイテムが買取可能な状態であるかを返す。
	 * 
	 * @param item
	 * @return アイテムが買取可能であればtrue
	 */
	private boolean isPurchaseableItem(final L1ItemInstance item) {
		if (item == null) {
			return false;
		}
		if (item.isEquipped()) { // 装備中であれば不可
			return false;
		}
		if (item.getEnchantLevel() != 0) { // 強化(or弱化)されていれば不可
			return false;
		}
		if (item.getBless() >= 128) { // 封印された装備
			return false;
		}

		return true;
	}

	private L1ShopItem getPurchasingItem(final int itemId) {
		for (final L1ShopItem shopItem : _purchasingItems) {
			if (shopItem.getItemId() == itemId) {
				return shopItem;
			}
		}
		return null;
	}

	public L1AssessedItem assessItem(final L1ItemInstance item) {
		final L1ShopItem shopItem = getPurchasingItem(item.getItemId());
		if (shopItem == null) {
			return null;
		}
		return new L1AssessedItem(item.getId(), getAssessedPrice(shopItem) , item);
	}

	private int getAssessedPrice(final L1ShopItem item) {
		return (int) (item.getPrice() * Config.RATE_SHOP_PURCHASING_PRICE / item.getPackCount());
	}

	/**
	 * インベントリ内の買取可能アイテムを査定する。
	 * 
	 * @param inv
	 *            査定対象のインベントリ
	 * @return 査定された買取可能アイテムのリスト
	 */
	public List<L1AssessedItem> assessItems(final L1PcInventory inv) {
		final List<L1AssessedItem> result = new ArrayList<L1AssessedItem>();
		for (final L1ShopItem item : _purchasingItems) {
			for (final L1ItemInstance targetItem : inv.findItemsId(item.getItemId())) {
				if (!isPurchaseableItem(targetItem)) {
					continue;
				}

				result.add(new L1AssessedItem(targetItem.getId(),getAssessedPrice(item) , targetItem));
			}
		}
		return result;
	}

	// TODO 全道具販賣by eric1300460
	public List<L1AssessedItem> allAssessItems(final L1PcInventory inv) {
		final List<L1AssessedItem> result = new ArrayList<L1AssessedItem>();
		for (final L1ItemInstance targetItem : inv.getItems()) {
			if (!isPurchaseableItem(targetItem)) {
				continue;
			}
			if (ShopTable.getInstance().getItemPrice(targetItem.getItemId()) > 0) {
				result.add(new L1AssessedItem(targetItem.getId(), ShopTable.getInstance().getItemPrice(targetItem.getItemId()) , targetItem));
			}

		}
		return result;
	}

	public L1AssessedItem allAssessItem(final L1ItemInstance item) {
		if(item == null){
			return null;
		}
		return new L1AssessedItem(item.getId(), ShopTable.getInstance().getItemPrice(item.getItemId()) , item);
	}

	// TODO 全道具販賣by eric1300460
	/**
	 * プレイヤーへアイテムを販売できることを保証する。
	 * 
	 * @return 何らかの理由でアイテムを販売できない場合、false
	 */
	private boolean ensureSell(final L1PcInstance pc, final L1ShopBuyOrderList orderList) {
		final int price = orderList.getTotalPriceTaxIncluded();
		// オーバーフローチェック
		if (!IntRange.includes(price, 0, 2000000000)) {
			// 総販売価格は%dアデナを超過できません。
			pc.sendPackets(new S_ServerMessage(904, "2000000000"));
			return false;
		}


		//永恆新增 -元寶商人 
		int bb;
		/*if (_npcId >= 600003 && _npcId <= 600010) { //元寶商城專用NPC的ID
           bb =80308; //元寶物品編號item_id*/
		//opqlo 推推幣
		if (_npcId >= Config.PUSH_NPCMINID && _npcId <= Config.PUSH_NPCMAXID) { 
			bb =Config.PUSH_ITEMID; 
			//opqlo 商城
		}else if(_npcId>=Config.GASH_NPCMINID && _npcId <=Config.GASH_NPCMAXID){
			bb =Config.GASH_ITEMID;
			//opqlo 支票
		}else if(_npcId >=Config.CHECK_NPCMINID && _npcId <= Config.CHECK_NPCMAXID){
			bb = Config.CHECK_ITEMID;
			//opqlo 其他貨幣1
		}else if(_npcId >=Config.OTHER_1_NPCMINID && _npcId <= Config.OTHER_1_NPCMAXID){
			bb = Config.OTHER_1_ITEMID;
			//opqlo 其他貨幣2
		}else if(_npcId >=Config.OTHER_2_NPCMINID && _npcId <= Config.OTHER_2_NPCMAXID){
			bb = Config.OTHER_2_ITEMID;
		}else if(_npcId==70035||_npcId==70041||_npcId==70042){
			bb = Config.CHECK_ITEMID;
		}else{
			bb =L1ItemId.ADENA;
		}
		if (!pc.getInventory().checkItem(bb, price)) {
			final L1Item item = ItemTable.getInstance().getTemplate(bb);
			if(item == null){
				return false;
			}
			//        l1j.eric.gui.J_Main.getInstance().addConsolPost(\"\"+price);
			//         \\f1アデナが不足しています。
			if (L1ItemId.ADENA == bb){ //add liumy
				pc.sendPackets(new S_ServerMessage(189));
			} else {
				pc.sendPackets(new S_SystemMessage("\\fY"+item.getName()+"不足"));
			}
			return false;
		} //永恆新增 -元寶商人 


		// 購入できるかチェック
		/*if (!pc.getInventory().checkItem(L1ItemId.ADENA, price)) {
			System.out.println(price);
			// \f1アデナが不足しています。
			pc.sendPackets(new S_ServerMessage(189));
			return false;	
		}*/

		// 重量チェック
		final int currentWeight = pc.getInventory().getWeight() * 1000;
		if (currentWeight + orderList.getTotalWeight() > pc.getMaxWeight() * 1000) {
			// アイテムが重すぎて、これ以上持てません。
			pc.sendPackets(new S_ServerMessage(82));
			return false;
		}
		// 個数チェック
		int totalCount = pc.getInventory().getSize();
		for (final L1ShopBuyOrder order : orderList.getList()) {
			final L1Item temp = order.getItem().getItem();
			if (temp.isStackable()) {
				if (!pc.getInventory().checkItem(temp.getItemId())) {
					totalCount += 1;
				}
			} else {
				totalCount += 1;
			}
		}
		if (totalCount > 180) {
			// \f1一人のキャラクターが持って歩けるアイテムは最大180個までです。
			pc.sendPackets(new S_ServerMessage(263));
			return false;
		}
		return true;
	}

	/**
	 * 地域税納税処理 アデン城・ディアド要塞を除く城はアデン城へ国税として10%納税する
	 * 
	 * @param orderList
	 */
	private void payCastleTax(final L1ShopBuyOrderList orderList) {
		final L1TaxCalculator calc = orderList.getTaxCalculator();

		final int price = orderList.getTotalPrice();

		final int castleId = L1CastleLocation.getCastleIdByNpcid(_npcId);
		int castleTax = calc.calcCastleTaxPrice(price);
		int nationalTax = calc.calcNationalTaxPrice(price);
		// アデン城・ディアド城の場合は国税なし
		if (castleId == L1CastleLocation.ADEN_CASTLE_ID
				|| castleId == L1CastleLocation.DIAD_CASTLE_ID) {
			castleTax += nationalTax;
			nationalTax = 0;
		}

		if (castleId != 0 && castleTax > 0) {
			final L1Castle castle = CastleTable.getInstance().getCastleTable(castleId);

			synchronized (castle) {
				int money = castle.getPublicMoney();
				if (2000000000 > money) {
					money = money + castleTax;
					castle.setPublicMoney(money);
					CastleTable.getInstance().updateCastle(castle);
				}
			}

			if (nationalTax > 0) {
				final L1Castle aden = CastleTable.getInstance().getCastleTable(L1CastleLocation.ADEN_CASTLE_ID);
				synchronized (aden) {
					int money = aden.getPublicMoney();
					if (2000000000 > money) {
						money = money + nationalTax;
						aden.setPublicMoney(money);
						CastleTable.getInstance().updateCastle(aden);
					}
				}
			}
		}
	}

	/**
	 * ディアド税納税処理 戦争税の10%がディアド要塞の公金となる。
	 * 
	 * @param orderList
	 */
	private void payDiadTax(final L1ShopBuyOrderList orderList) {
		final L1TaxCalculator calc = orderList.getTaxCalculator();

		final int price = orderList.getTotalPrice();

		// ディアド税
		final int diadTax = calc.calcDiadTaxPrice(price);
		if (diadTax <= 0) {
			return;
		}

		final L1Castle castle = CastleTable.getInstance().getCastleTable(L1CastleLocation.DIAD_CASTLE_ID);
		synchronized (castle) {
			int money = castle.getPublicMoney();
			if (2000000000 > money) {
				money = money + diadTax;
				castle.setPublicMoney(money);
				CastleTable.getInstance().updateCastle(castle);
			}
		}
	}

	/**
	 * 町税納税処理
	 * 
	 * @param orderList
	 */
	private void payTownTax(final L1ShopBuyOrderList orderList) {
		final int price = orderList.getTotalPrice();

		// 町の売上
		if (!L1World.getInstance().isProcessingContributionTotal()) {
			final int town_id = L1TownLocation.getTownIdByNpcid(_npcId);
			if (town_id >= 1 && town_id <= 10) {
				TownTable.getInstance().addSalesMoney(town_id, price);
			}
		}
	}

	// XXX 納税処理はこのクラスの責務では無い気がするが、とりあえず
	private void payTax(final L1ShopBuyOrderList orderList) {
		payCastleTax(orderList);
		payTownTax(orderList);
		payDiadTax(orderList);
	}

	/**
	 * 販売取引
	 */
	private void sellItems(final L1PcInstance pc,final L1PcInventory inv, final L1ShopBuyOrderList orderList) {

		int bb;
		if (_npcId >= Config.PUSH_NPCMINID && _npcId <= Config.PUSH_NPCMINID) {//opqlo 推推幣
			bb =Config.PUSH_ITEMID; 
		}else if(_npcId >=Config.GASH_NPCMINID && _npcId <= Config.GASH_NPCMAXID){//opqlo 商城
			bb = Config.GASH_ITEMID;
		}else if(_npcId >= Config.CHECK_NPCMINID && _npcId <=Config.CHECK_NPCMAXID){//opqlo 支票
			bb= Config.CHECK_ITEMID;
		}else if(_npcId >= Config.OTHER_1_NPCMINID && _npcId <= Config.OTHER_1_NPCMAXID){//opqlo 其他貨幣1
			bb =Config.OTHER_1_ITEMID;
		}else if(_npcId >= Config.OTHER_2_NPCMINID && _npcId <= Config.OTHER_2_NPCMAXID){//opqlo 其他貨幣2
			bb =Config.OTHER_2_ITEMID;
		}else if(_npcId==70035||_npcId==70041||_npcId==70042){
			bb = Config.CHECK_ITEMID;
		}else{
			bb =L1ItemId.ADENA;
		}
		final int totalPrice = orderList.getTotalPriceTaxIncluded();
		L1ItemInstance logitem =null;
		String logname = null ;
		if(bb!=L1ItemId.ADENA){
			logitem = pc.getInventory().findItemId(bb);
			if(logitem !=null){
				logname=new StringBuilder().append(logitem.getName()).append(" (").append(String.format("%,d", logitem.getCount())).append(")").toString(); 
			}
		}
		if ( !inv.consumeItem(bb, totalPrice)) {
			//if (!inv.consumeItem(L1ItemId.ADENA,orderList.getTotalPriceTaxIncluded())) {
			throw new IllegalStateException("因不足對購買所需的金幣而不能消費。"); // (原文)購入に必要なアデナを消費できませんでした。
		}else{
			String logtime = null;
			if(bb!=L1ItemId.ADENA){
//				logtime = new StringBuilder().append(GetNowTime.GetNowYear()-2000).append("-").append(GetNowTime.GetNowMonth()+1).append("-").append(GetNowTime.GetNowDay()).toString();
//				sb=new StringBuilder().append(pc.getNetConnection().getIp().toString()).append(" 【 ").append(pc.getName()).append(" 】時間:")
//						.append(new Timestamp(System.currentTimeMillis())).append(" 購買物品\r\n持有貨幣:").append(logname).append("\r\n");
				logtime =GetNowTime.GetFormatDate();
				sb=new StringBuilder().append(pc.getNetConnection().getIp().toString()).append(" 【 ").append(pc.getName()).append(" 】時間:")
						.append(new Timestamp(System.currentTimeMillis())).append(" 購買物品\r\n持有貨幣:").append(logname).append("\r\n");
			}
			for (final L1ShopBuyOrder order : orderList.getList()) {
				int column =0;
				final int itemId = order.getItem().getItemId();
				final int amount = order.getCount();
				//final L1ItemInstance Srcitem = ItemTable.getInstance().createItem(itemId);
				final L1ItemInstance item = ItemTable.getInstance().createItem(itemId);
				//final L1ItemInstance item =inv.storeItem(Srcitem);
				// 道具天數刪除系統
				final	int deleteDay = order.getDeleteDay(); // 道具天數刪除系統(指定天數)
				final Timestamp deleteDate = order.getDeleteDate(); // 道具天數刪除系統(指定日期)
				// 道具天數刪除系統
				if (deleteDay > 0) { // ● 指定天數
					Timestamp delDay = new Timestamp(System.currentTimeMillis()+ (86400000 * deleteDay));
					item.setDeleteDate(delDay);
				}else if (deleteDate != null) { // ● 指定日期
					item.setDeleteDate(deleteDate);
				}
				if (item.getDeleteDate() != null) {
					pc.sendPackets(new S_ServerMessage(166, item.getName() + " (" + amount + ") 使用期限:" +item.getDeleteDate()));
				}// end
				if (item.getItemId() == 40309) {// Race Tickets
					item.setItem(order.getItem().getItem());
					L1BugBearRace.getInstance().setAllBet(L1BugBearRace.getInstance().getAllBet()+ (amount * order.getItem().getPrice()));
					String[] runNum = item.getItem().getIdentifiedNameId().split("-");
					int trueNum = 0;
					for (int i = 0; i < 5; i++) {
						if (L1BugBearRace.getInstance().getRunner(i).getNpcId() - 91350 == (Integer.parseInt(runNum[runNum.length - 1]) - 1)) {
							trueNum = i;
							break;
						}
					}
					L1BugBearRace.getInstance().setBetCount(trueNum,L1BugBearRace.getInstance().getBetCount(trueNum)+ amount);
				}else if (_npcId == 70068 || _npcId == 70020) {
					item.setIdentified(false);
					final int chance = Random.nextInt(100) + 1;
					if (chance <= 15) {
						item.setEnchantLevel(-2);
					} else if (chance >= 16 && chance <= 30) {
						item.setEnchantLevel(-1);
					} else if (chance >= 31 && chance <= 70) {
						item.setEnchantLevel(0);
					} else if (chance >= 71 && chance <= 87) {
						item.setEnchantLevel(Random.nextInt(2) + 1);
					} else if (chance >= 88 && chance <= 97) {
						item.setEnchantLevel(Random.nextInt(3) + 3);
					} else if (chance >= 98 && chance <= 99) {
						item.setEnchantLevel(6);
					} else if (chance == 100) {
						item.setEnchantLevel(7);
					}
				}else if(_npcId == 700008){
					item.setBless(129);
					column += L1PcInventory.COL_BLESS;

				}else if(bb == Config.GASH_ITEMID){
					final int itemtype2 = item.getItem().getType2();
					if(itemtype2!=0){
						if(itemtype2==1){//opqlo 商城武器 加成
							item.setEnchantLevel(30);
						}else if(itemtype2==2){
							final int type = item.getItem().getType();
							//1:helm, 2:armor, 3:T, 4:cloak, 5:glove, 6:boots, 7:shield, 8:amulet, 9:ring, 10:belt, 11:ring2, 12:earring
							switch(type){
							case 1:
								item.setEnchantLevel(10);
								break;
							case 2:
								item.setEnchantLevel(10);
								break;
							case 5:
								item.setEnchantLevel(10);
								break;
							case 6:
								item.setEnchantLevel(10);
								break;
							}
							switch(item.getItemId()){
							case 810006:// 皇天項鍊
								item.setaddHp(1500);
								item.setaddMp(1000);
								item.setExpUp(1.5);
								column += L1PcInventory.COL_ADDHP + L1PcInventory.COL_ADDMP + L1PcInventory.COL_Other;
								break;
							case 810065://	LV80神官英雄斗篷
							case 810066://	LV80武官英雄斗篷
							case 810067://	LV80神射英雄斗篷
								item.setLevel(80);
								column +=L1PcInventory.COL_LEVEL;
								break;
							}

						}
						column += L1PcInventory.COL_BLESS;
						item.setBless(0);
					}
				}
				if(order.getRemainingTime()>0){
					item.setRemainingTime(order.getRemainingTime());
					column +=L1PcInventory.COL_REMAINING_TIME;
				}
				item.setCount(amount);
				item.setIdentified(true);
				final L1ItemInstance newitem =inv.storeItem(item);
				if(column>0){
					pc.getInventory().updateItem(newitem,column);
					pc.getInventory().saveItem(newitem,column);
				}
				if(bb!=L1ItemId.ADENA){
					sb.append(item.getViewName()).append(" 金額「").append(order.getItem().getPrice() * amount).append("」 流水號: ").append(item.getId()).append("\r\n");
				}
			}
			if(bb!=L1ItemId.ADENA && logtime !=null){
				sb.append("共 ").append(totalPrice).append("	身上剩下:").append(logitem.getName()).append(" (").append(String.format("%,d", logitem.getCount())).append(")").append("\r\n");
				buyLog(bb , logtime);
			}
		}
	}

	/**
	 * プレイヤーに、L1ShopBuyOrderListに記載されたアイテムを販売する。
	 * 
	 * @param pc
	 *            販売するプレイヤー
	 * @param orderList
	 *            販売すべきアイテムが記載されたL1ShopBuyOrderList
	 */
	public void sellItems(final L1PcInstance pc, final L1ShopBuyOrderList orderList) {
		if (!ensureSell(pc, orderList)) {
			return;
		}else if (orderList.getList().isEmpty()){
			return;
		}
		sellItems(pc,pc.getInventory(), orderList);
		payTax(orderList);
	}

	/**
	 * L1ShopSellOrderListに記載されたアイテムを買い取る。
	 * 
	 * @param orderList
	 *            買い取るべきアイテムと価格が記載されたL1ShopSellOrderList
	 */
	public void buyItems(final L1ShopSellOrderList orderList,final boolean Check) {//opqlo 賭肥支票
		//	public void buyItems(final L1ShopSellOrderList orderList) {
		final L1PcInstance pc = orderList.getPc();//取得角色物件
		final L1PcInventory inv = pc.getInventory();//取得角色背包
		final int maxcount = 2000000000; //最大數量上限 20億
		final L1ItemInstance item ;
		if(!Check){
			item = inv.findItemId(L1ItemId.ADENA); //金幣
		}else{
			item = inv.findItemId(60308); //支票
		}
		long totalPrice = 0;//售出總價格
		for (final L1ShopSellOrder order : orderList.getList()) { //取得購物清單中的物品

			long count = order.getCount(); //取得售出清單中的物品數量
			long invCount = 0;
			if(item != null){
				invCount = item.getCount();
			}
			if(count > invCount){ //如果售出清單數量大於身上持有量
				count = invCount; //等於身上數量
			}
			if(count <=0){
				continue;
			}
			totalPrice += (order.getItem().getAssessedPrice() * count); //取得該物品售出總價格

			if(invCount + totalPrice >maxcount){ //身上金幣數量 + 總價格 超出20億
				pc.sendPackets(new S_SystemMessage("身上金幣不可超過20億")); //發送通知訊息
				totalPrice -= (order.getItem().getAssessedPrice() * count); //將該物品之價格從總金額中扣除
				//	orderList.getList().clear();//購物清單清空
				break;//跳出迴圈
			}
			inv.removeItem(order.getItem().getTargetId(),count);
			//	inv.removeItem(item,count);//一切正常則扣除身上該物品數量
		}


		//totalPrice = IntRange.ensure(totalPrice, 0, 2000000000);
		if (0 < totalPrice) { //如果總金額大於 0
			if(!Check){
				inv.storeItem(L1ItemId.ADENA, (int) totalPrice); //給予相對應的金幣
			}else{
				inv.storeItem(60308, (int) totalPrice); //給予相對應的支票	
			}
		}
	}

	public L1ShopBuyOrderList newBuyOrderList() {
		return new L1ShopBuyOrderList(this);
	}

	public L1ShopSellOrderList newSellOrderList(final L1PcInstance pc) {
		return new L1ShopSellOrderList(this, pc);
	}


	/**TODO 購入記錄 by opqlo*/
	private static final Logger _log = Logger.getLogger(L1Shop.class.getName());
	private StringBuilder sb ;
	private static final String SP = "\r\n▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇\r\n";

	private  void buyLog(final int coinage , final String logtime){

		BufferedWriter out = null;
		try {

			if(coinage== Config.PUSH_ITEMID)
				out = new BufferedWriter(new FileWriter(Config.LOG_LOCATION+"記錄/特殊商店/推推幣/購買記錄"+logtime+".txt", true));

			else if(coinage == Config.GASH_ITEMID)
				out = new BufferedWriter(new FileWriter(Config.LOG_LOCATION+"記錄/特殊商店/商幣/購買記錄"+logtime+".txt", true));
			else if(coinage == Config.CHECK_ITEMID)

				out = new BufferedWriter(new FileWriter(Config.LOG_LOCATION+"記錄/特殊商店/支票/購買記錄"+logtime+".txt", true));
			else if(coinage == Config.OTHER_1_ITEMID)
				out = new BufferedWriter(new FileWriter(Config.LOG_LOCATION+"記錄/特殊商店/特殊１/購買記錄"+logtime+".txt", true));
			else if(coinage == Config.OTHER_2_ITEMID)
				out = new BufferedWriter(new FileWriter(Config.LOG_LOCATION+"記錄/特殊商店/特殊２/購買記錄"+logtime+".txt", true));
			if(out!=null){
				sb.append(SP);
				out.write(sb.toString());
			}
		} catch (IOException e) {
			_log.log(Level.SEVERE , e.getLocalizedMessage() , e);
		}finally{
			StreamUtil.close(out);
		}
	}

	/**TODO 購入記錄 by opqlo*/
}
